jQuery.fn.extend({
	/**
	 * 将serializeArray产生的结果封装成{{property, value}, }的Json格式对象
	 * @returns
	 */
	form2Json:function(prefix){
		var json = {};
		var fields = jQuery(this).serializeArray();
		jQuery.each( fields, function(i, field){
			var key = field.name;
			if(prefix){
				// 这个方式不是很健壮，遇到特殊情况，需要完善这里
				key = key.replace( prefix + '\.', '' );
			}
			json[key] = field.value;
		});
		return json;
	},
	//checkbox、radio等应该还有问题，暂时先这么写
	form2Criteria:function(option){
		option = option || {};
		var prefix = option.prefix;
		var fuzzyFields = option.fuzzyFields || [];
		var ignoreFields = option.ignoreFields || [];
		
		var criteria = '';
		var fields = jQuery(this).serializeArray();
		var fuzzy = {};
		for (var i = 0; i < fuzzyFields.length; i++) {
			fuzzy[fuzzyFields[i]] = 1;
		}
        var ignore = {};
		for (var i = 0; i < ignoreFields.length; i++) {
			ignore[ignoreFields[i]] = 1;
		}  
		jQuery.each( fields, function(i, field){
			if (field.value) {
				var key = field.name;
				if(prefix){
					// 这个方式不是很健壮，遇到特殊情况，需要完善这里
					key = key.replace( prefix + '\.', '' );
				}
				if (ignore[key] == 1) {
				    return;
				}
				if (criteria != '') {
					criteria += ' and ';
				}
				if (fuzzy[key] == 1) {
					criteria += field2ColumnName(key) + " like '%" + field.value + "%' ";
				} else {
					criteria += field2ColumnName(key) + " = '" + field.value + "' ";
				}
			}

		});
		return criteria;
	},
	// 与form.reset的区别,可以清空hidden input
	clearForm:function() {
	    jQuery(this).find(':input').each(function() {
	        switch(this.type) {
	            case 'password':
	            case 'select-multiple':
	            case 'select-one':
	            case 'text':
	            case 'textarea':
	            case 'hidden':
	                jQuery(this).val('');
	                break;
	            case 'checkbox':
	            case 'radio':
	                this.checked = false;
	        }
	    });
	},

	/**
	 * 隐藏当前html片断,并且显示loading图片
	 * @returns
	 */
	loading:function(){
		jQuery(this).before('<span id=\'loading_bar\'>loading...</span>');
	},
	/**
	 * 在某个元素内部显示loading
	 */
	innerLoading:function(loadingMsg) {
		if(loadingMsg) {
			jQuery(this).html('<div class="inner-loading">'+loadingMsg+'</div>');
		}else{
			jQuery(this).html('<div class="loading"></div>');
		}
		jQuery(this).show();
		return this;
	},
	/**
	 * 高亮某个部分，表示这部分发生了变化
	 */
	highlight: function() {
		dwr.util.yellowFadeHighlightHandler(jQuery(this));
	}
});


function hideloading(){
	jQuery('#loading_bar').remove();
}

function field2ColumnName(fieldName){
	var columnName = '';
	var str = new Array();
	for (var i = 0; i < fieldName.length; i++) {
		str[i] = fieldName.substring(i,i+1);
		if (/[A-Z]/.test(str[i])) {
			columnName += '_' + str[i].toLowerCase();
		} else {
			columnName += str[i].toLowerCase();
		}
	}
	return columnName;
}

!function ($) {
	
	var _CACHE_DATA = {};
	
	var KEY = {
		    UP: 38,
		    DOWN: 40,
		    DEL: 46,
		    TAB: 9,
		    RETURN: 13,
		    ESC: 27,
		    COMMA: 188,
		    PAGEUP: 33,
		    PAGEDOWN: 34,
		    BACKSPACE: 8	
	};
	
	function defaultGetLength(text) {
		return text && text.length? jQuery.trim(text).length : 0;
	}
	
	
	//字数限制
	$.fn.textCounter = function (options) {
		if(isNaN(options)) {
			options = options || {};
		}else{
			options = {
				count: options	
			};
		}
		var getLength = (typeof options.getTextLength == 'function'? options.getTextLength : defaultGetLength),
			displayTextCounterFunc = function(displayAt, canInputTextCount){
				if(canInputTextCount >= 0) {
					displayAt.html('您还可以输入<em>'+ canInputTextCount +'</em>字').show();
				}else{
					displayAt.html('已经超过<em class="overlimit">'+ (canInputTextCount * -1) +'</em>字').show();
				}
			},
			alwaysDisplay = options.alwaysDisplay === true? true : false;
		
		return this.each(function () {
			var $this = jQuery(this),
				displayAt = options.displayAt,
				maxLength = (options.count || $this.attr('maxlength')) || 0;
			if(!maxLength || isNaN(maxLength) || maxLength == 0) {
				return;
			}
			//初始化显示信息的位置
			if(displayAt) {
				displayAt = jQuery(displayAt).addClass('textCounter');
			}else{
				displayAt = jQuery('<div class="textCounter"></div>');
				$this.after(displayAt);
			}
			if(alwaysDisplay){
				displayTextCounterFunc(displayAt, maxLength - getLength($this.val()));
			}else{
				//离开焦点的时候自动隐藏，如果输入有误的话则不隐藏
				jQuery(this).blur(function(){
					if(displayAt.find('em.overlimit').length == 0) {
						displayAt.hide();
					}
				});
			}
			jQuery(this).bind('focus keyup', function(){
				var canInputTextCount = maxLength - getLength($this.val());
				displayTextCounterFunc(displayAt, canInputTextCount);
				if(options.callback == 'function') {
					options.callback(canInputTextCount);
				}
			});
		});
	};
	
	/**
	 * 生成分页标签，为了方便添加，这里直接从jquery.pagination.js拷贝过来了
	 * This jQuery plugin displays pagination links inside the selected elements.
	 *
	 * @author Gabriel Birke (birke *at* d-scribe *dot* de)
	 * @version 1.2
	 * @param {int} maxentries Number of entries to paginate
	 * @param {Object} opts Several options (see README for documentation)
	 * @return {Object} jQuery Object
	 */
	jQuery.fn.pagination = function(maxentries, opts){
		opts = jQuery.extend({
			items_per_page:10,
			num_display_entries:10,
			current_page:0,
			num_edge_entries:0,
			link_to:"javascript:void(0)",
			prev_text:"上一页",
			next_text:"下一页",
			ellipse_text:"...",
			prev_show_always:true,
			next_show_always:true,
			callback:function(){return false;}
		},opts||{});
		
		return this.each(function() {
			/**
			 * Calculate the maximum number of pages
			 */
			function numPages() {
				return Math.ceil(maxentries/opts.items_per_page);
			}
			
			/**
			 * Calculate start and end point of pagination links depending on 
			 * current_page and num_display_entries.
			 * @return {Array}
			 */
			function getInterval()  {
				var ne_half = Math.ceil(opts.num_display_entries/2);
				var np = numPages();
				var upper_limit = np-opts.num_display_entries;
				var start = current_page>ne_half?Math.max(Math.min(current_page-ne_half, upper_limit), 0):0;
				var end = current_page>ne_half?Math.min(current_page+ne_half, np):Math.min(opts.num_display_entries, np);
				return [start,end];
			}
			
			/**
			 * This is the event handling function for the pagination links. 
			 * @param {int} page_id The new page number
			 */
			function pageSelected(page_id, evt){
				current_page = page_id;
				drawLinks();
				var continuePropagation = opts.callback(page_id, panel);
				if (!continuePropagation) {
					if (evt.stopPropagation) {
						evt.stopPropagation();
					}
					else {
						evt.cancelBubble = true;
					}
				}
				return continuePropagation;
			}
			
			/**
			 * This function inserts the pagination links into the container element
			 */
			function drawLinks() {
				panel.empty();
				var interval = getInterval();
				var np = numPages();
				// This helper function returns a handler function that calls pageSelected with the right page_id
				var getClickHandler = function(page_id) {
					return function(evt){ return pageSelected(page_id,evt); }
				}
				// Helper function for generating a single link (or a span tag if it's the current page)
				var appendItem = function(page_id, appendopts){
					page_id = page_id<0?0:(page_id<np?page_id:np-1); // Normalize page id to sane value
					appendopts = jQuery.extend({text:page_id+1, classes:""}, appendopts||{});
					if(page_id == current_page){
						var lnk = jQuery("<span class='current'>"+(appendopts.text)+"</span>");
					}
					else
					{
						var lnk = jQuery("<a>"+(appendopts.text)+"</a>")
							.bind("click", getClickHandler(page_id))
							.attr('href', opts.link_to.replace(/__id__/,page_id));
							
							
					}
					if(appendopts.classes){lnk.addClass(appendopts.classes);}
					panel.append(lnk);
				}
				// Generate "Previous"-Link
				if(opts.prev_text && (current_page > 0 || opts.prev_show_always)){
					appendItem(current_page-1,{text:opts.prev_text, classes:"prev"});
				}
				// Generate starting points
				if (interval[0] > 0 && opts.num_edge_entries > 0)
				{
					var end = Math.min(opts.num_edge_entries, interval[0]);
					for(var i=0; i<end; i++) {
						appendItem(i);
					}
					if(opts.num_edge_entries < interval[0] && opts.ellipse_text)
					{
						jQuery("<span>"+opts.ellipse_text+"</span>").appendTo(panel);
					}
				}
				// Generate interval links
				for(var i=interval[0]; i<interval[1]; i++) {
					appendItem(i);
				}
				// Generate ending points
				if (interval[1] < np && opts.num_edge_entries > 0)
				{
					if(np-opts.num_edge_entries > interval[1]&& opts.ellipse_text)
					{
						jQuery("<span>"+opts.ellipse_text+"</span>").appendTo(panel);
					}
					var begin = Math.max(np-opts.num_edge_entries, interval[1]);
					for(var i=begin; i<np; i++) {
						appendItem(i);
					}
					
				}
				// Generate "Next"-Link
				if(opts.next_text && (current_page < np-1 || opts.next_show_always)){
					appendItem(current_page+1,{text:opts.next_text, classes:"next"});
				}
			}
			
			// Extract current_page from options
			var current_page = opts.current_page;
			// Create a sane value for maxentries and items_per_page
			maxentries = (!maxentries || maxentries < 0)?1:maxentries;
			opts.items_per_page = (!opts.items_per_page || opts.items_per_page < 0)?1:opts.items_per_page;
			// Store DOM element for easy access from all inner functions
			var panel = jQuery(this);
			// Attach control functions to the DOM element 
			this.selectPage = function(page_id){ pageSelected(page_id);}
			this.prevPage = function(){ 
				if (current_page > 0) {
					pageSelected(current_page - 1);
					return true;
				}
				else {
					return false;
				}
			}
			this.nextPage = function(){ 
				if(current_page < numPages()-1) {
					pageSelected(current_page+1);
					return true;
				}
				else {
					return false;
				}
			}
			// When all initialisation is done, draw the links
			drawLinks();
	        // call callback function
	        opts.callback(current_page, this);
		});
	};
	
	//选择控件
	$.fn.selectgroup = function (options) {
		options = options || {};
		options.selected = options.selected || [];
		
		return this.each(function () {
			var $thisobj = jQuery(this);
			//如果已经初始化过了就不需要了
			if($thisobj.hasClass('selectgroup')) {
				return;
			};
			var hiddenObj = null;
			if(options.hiddenId) {
				hiddenObj = (typeof options.hiddenId == 'string') ? jQuery('#' + options.hiddenId) : jQuery(options.hiddenId);
				options.separator = options.separator || ',';
				hiddenObj.val(options.selected.join(options.separator));
			}
			if(!options.data) {
				alert('请指定data属性');
				return;
			}
 			var html = '<ul class="clear selectgroup'+ (options.multi? ' multi' : '') +'">';
			$.each(options.data, function(index, ele){
				var text = (typeof ele == 'object'? ele.text: ele),
				    value = (typeof ele == 'object'? ele.value: ele),
				    selected = (options.selected.indexOf(value) >= 0);
				html += '<li'+ (selected? ' class="selected"' : '') +' data-value="'+ value +'" title="'+ text +'"><a href="javascript:void(0)">'+ text +'</a>'+ (selected? '<i>已选中</i>' : '') +'</li>';
			});
			html += '</ul>';
			$thisobj.html(html);
			//将选择后的值放在临时变量中，如果已经设置了隐藏字段的话，则点击的时候同时设置隐藏字段的值
			$thisobj.find('li').click(function(){
				var hasSelected = jQuery(this).hasClass('selected'),
				    val = jQuery(this).attr('data-value'),
				    text = jQuery(this).children('a').text();
				if(typeof val == 'undefined') {
					//默认为文本
					val = text;
				}
				if(hasSelected) {
					if(options.mustSelect) {
						//如果是必须选择的话不能取消选择所有选项
						if($thisobj.find('.selected').length <= 1) {
							return;
						}
					}
					jQuery(this).removeClass('selected');
					jQuery(this).children('i').remove();
					
					var filterValues = [];
					$.each(options.selected, function(index, ele){
						if(ele != val) {
							filterValues.push(ele);
						}
					});
					options.selected = filterValues;
					//取消时触发的事件
					if(typeof options.onCancelSelect == 'function') {
						options.onCancelSelect(val, text);
					}
				}else{
					if(!jQuery(this).parent().hasClass('multi')) {
						var selectedObj = jQuery(this).parent().find('li.selected');
						selectedObj.removeClass('selected');
						selectedObj.children('i').remove();
						//取消时触发的事件
						if(typeof options.onCancelSelect == 'function' && selectedObj.length > 0) {
							var cancelVal = selectedObj.attr('data-value'),
							    cancelText = selectedObj.children('a').text();
							if(typeof cancelVal == 'undefined') {
								cancelVal = cancelText;
							}
							options.onCancelSelect(cancelVal, cancelText);
						}
						
						options.selected = [ val ];
					}else{
						if(options.selected.indexOf(val) < 0) {
							options.selected.push(val);
						}
					}
					//选中时触发的事件
					if(typeof options.onSelect == 'function') {
						options.onSelect(val, text);
					}
					jQuery(this).addClass('selected').append('<i>已选中</i>');
				}
				if(hiddenObj) {
					hiddenObj.val(options.selected.join(options.separator));
				}
			});
		});
		
	};
	
	/*初始化文件上传界面*/

	$.fn.initFileUpload=function(options){	
		var wrap = '<div class="file-upload"></div>';
		var btn_value = options.btnValue || "选择文件";
		var btn_only = options.btnOnly || false;
		var type = options.type;  //限制的文件类型
		var fstr='<input type="text"class="i-txt fake-file"readonly="readonly"/><input type="button" class="btn chose-file"value="'+btn_value+'"/>';
		if(btn_only){
			var btn_class = (options.btnClass||'') + " chose-file" || "btn chose-file";
			fstr = '<input type="button" class="'+btn_class+'" value="'+btn_value+'"/>';
		}
		//截取上传文件名
		function getFileName(str){
			return str.match(/[^\/|^\\]*$/)[0];
		}
		//判断值是否在数组中
		function in_array(val,arr){
			var type = typeof val;
			if(type == "string" || type == "number"){
				for(var i in arr){
					if(arr[i] == val)
						return true;
				}
			}
			return false;
		}

		return this.each(function(){
			var $this = jQuery(this);
			/*用于替换原始input对象,简单复制所以避免在input标签上绑定过多属性.
			 *临时方法不够完善
			 */
			var cloneMod = jQuery('<input>',{
				'type': 'file',
				'name': $this.attr('name'),
				'class': $this.attr('class'),
				'id': $this.attr('id')
			});

			if($this.attr("data-initfile") == "true") {
				return false;
			}
			$this.wrap(wrap);
			jQuery(fstr).insertAfter($this);

			var fparent = $this.parent();
			var fakeFile=fparent.find(".fake-file");
			var fileName = "";
			if(fakeFile && options.width){
				fakeFile.width(options.width);
			}
			var fwidth = fparent.find(".fake-file").length > 0 ? fparent.find(".fake-file").width() : 0;
			fparent.width(fwidth + fparent.find(".chose-file").outerWidth());//12为text的margin+padding+border
			
			function changeHandler(callback){
				var cloneObj = cloneMod.clone();
				var fileInput = jQuery(this);

				if(fileInput.val() == '') return;
				if(undefined != type){
					var fileType = fileInput.val().toLowerCase().substring(fileInput.val().lastIndexOf(".")+1);
					if(!in_array(fileType,type)){
						Message.error('请选择以下类型的文件进行上传：'+type);
						return false;
					}
				}
				if(!btn_only){
					fakeFile.val(fileInput.val());
				}
				fileName = getFileName(fileInput.val());
				
				if(typeof callback ==="function"){
					callback(fileName);
				}

				fileInput.replaceWith(cloneObj);
				
				cloneObj.on('change' ,function(){
					changeHandler.call(cloneObj, callback);
				})
			}

			$this.on('change', function(e){
				changeHandler.call($this, options.callBack);
			})
			$this.attr("data-initfile",true);
		});
	};
	$.fn.TextAreaExpander = function(minHeight, maxHeight) {

		if(arguments[0] == 'refresh' && this[0].Initialized === true) {
			this[0].refreshTextarea && this[0].refreshTextarea(this[0]);
			return;
		}
		var hCheck = !($.browser.msie || $.browser.opera);

		// resize a textarea
		function ResizeTextarea(e) {
			// event or initialize element?
			e = e.target || e;

			// find content length and box width
			var vlen = e.value.length,
				ewidth = e.offsetWidth,
				epdt = parseInt($(e).css('padding-top')),
				epdb = parseInt($(e).css('padding-bottom'));
			if (vlen != e.valLength || ewidth != e.boxWidth) {

				if (hCheck && (vlen < e.valLength || ewidth != e.boxWidth)) e.style.height = "0px";
				var h = Math.max(e.expandMin, Math.min(e.scrollHeight, e.expandMax));
				e.style.overflow = (e.scrollHeight > h ? "auto" : "hidden");
				
				if(e.Initialized)
					e.style.height = h - epdt - epdb + "px";
				else
					e.style.height = h - epdt - epdb + 2 + "px";

				e.valLength = vlen;
				e.boxWidth = ewidth;
			}

			return true;
		};

		// initialize
		this.each(function() {

			// is a textarea?
			if (this.nodeName.toLowerCase() != "textarea") return;
			this.refreshTextarea = function(e){
				ResizeTextarea(this);
			}
			// set height restrictions
			var p = this.className.match(/expand(\d+)\-*(\d+)*/i);
			this.expandMin = minHeight || (p ? parseInt('0'+p[1], 10) : 0);
			this.expandMax = maxHeight || (p ? parseInt('0'+p[2], 10) : 99999);

			// initial resize
			//ResizeTextarea(this);

			// zero vertical padding and add events
			if (!this.Initialized) {
				this.Initialized = true;
				$(this).bind("keyup", ResizeTextarea).bind("focus", ResizeTextarea);
			}
		});

		return this;
	};
}(window.jQuery);